import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.rmi.*;


/*****************************************************************************
 * File: Manager.java
 * Author:  Todd Silvia & Phil Pilosi
 * Class:   CS 441 - Spring 2011
 * Project: 2 - Distributed Booking Agent, with RMI
 * Date:    February 28th 2011
 * Description: <Insert Description Here>
 */

public class Manager {
	BufferedReader keyboardIn;					//Used to read input from keyboard
	ServerFunc myRemote;						//Object reference to the rmi/server functions
	ClientCallbackInterface clientRemote;

	public Manager() {
		keyboardIn = new BufferedReader(new InputStreamReader(System.in));
	}//END Manager()
	
	public void newMain(String[] args)
	{
		//Welcome user!
		this.welcomeMessage();
		//Setup RMI 
		this.startConnection();
		//Wait for input function!
		try
		{
			this.waitForCommand();
		}
		catch(Exception e)
		{
			System.out.println("Error: " + e);
		}
		//this.waitForCommand();


	}//END newMain()

	public static void main(String[] args)
	{
		Manager newManager = new Manager();
		newManager.newMain(args);
	}//END main()

	public void welcomeMessage()
	{
		System.out.println("");
	}//END welcomeMessage

	/*****************************************************************************
	 * Connects to the rmi and sets up any connection criteria.
	 */
	public void startConnection() 
	{
		String serverName = "127.0.0.1";
		String portNum = ":13337";

		String rmiName = "rmi://" + serverName + portNum +"/dataServer"; //Builds the string for the server to connect to.

		System.out.println("Connecting to data server");
	
		try
		{
			myRemote = (ServerFunc)Naming.lookup(rmiName);//Actually attempt to connect to server.
			
			clientRemote = new ClientCallbackImp();//Send server reference of this manager to be added to a broadcast list.		
			
			//Given this is the manager after making connection invoke the Server.connect()
			//method to be added to broadcast list.
			myRemote.connect(clientRemote);  

		}
		catch(Exception e)
		{
			System.out.println("Error: " + e);

			System.out.println("Program shutting down, due to failing to connect to server");
			System.out.println("Please restart the application and try again.");
			System.out.println("If the problem continues, please call the system administrator");
			System.out.println("of your server to resolve the issue");
			System.exit(-1);
		}

		
	}//END startConnection()
	
	/*****************************************************************************
	 * Waits for the user to enter a command to determine the action to be taken 
	 * by the client. Also checks for proper input, e.g. NumberFormatException and
	 * not enough arguments
	 */
	public void waitForCommand() throws IOException {
		while ( true ) {
			int eventNumber = 0;
			//Read in command from the user
			String commandEntered = keyboardIn.readLine();
			
			//If the user wants to add an event to the server
			if(commandEntered.equalsIgnoreCase("add")) {
				String description = keyboardIn.readLine();
				if(description.length() < 1) {
					System.out.println("Command failed, no description entered!");
					continue;
				}
				
				int spaceRequest;
				try {
					spaceRequest = Integer.parseInt(keyboardIn.readLine().trim());
				} catch (NumberFormatException e) {
					System.out.println("You did enter a proper amount to request!");
					continue;
				}
				addEvent(description, spaceRequest);
				
			} else {
				StringTokenizer strTok = new StringTokenizer(commandEntered);
				if(strTok.hasMoreTokens()) {
					String command1 = strTok.nextToken();
					
					//If the user wants to view all events on the server
					if(command1.equalsIgnoreCase("view")) {
						viewEvents();
					//The suer wants to reserve space in an event
					} else if( command1.equalsIgnoreCase("reserve")) {
						int spaceTaken;
						if(strTok.countTokens() != 3) {
							System.out.println("You did not enter the proper number of arguments!");
							continue;
						}
						try {
							eventNumber = Integer.parseInt(strTok.nextToken().trim());
							spaceTaken = Integer.parseInt(strTok.nextToken().trim());
						} catch (NumberFormatException e) {
							System.out.println("You did not enter a numerical number correctly!");
							continue;
						}
						String theName = strTok.nextToken();
						if(theName.length() < 1) {
							System.out.println("You did not enter a valid name length!");
							continue;
						}
						makeReservation(eventNumber, spaceTaken, theName);
					
					//User wants to delete a reservation from an event
					} else if(command1.equalsIgnoreCase("delete")) {
						int confirmationNumber;
						if(strTok.countTokens() != 2) {
							System.out.println("You did not enter proper number of arguments!");
							continue;
						}
						try {
							eventNumber = Integer.parseInt(strTok.nextToken().trim());
							confirmationNumber = Integer.parseInt(strTok.nextToken().trim());
						}catch (NumberFormatException e) {
							System.out.println("You did not enter a numerical number correctly!");
							continue;
						}
						deleteReservation(eventNumber, confirmationNumber);
						
					//User wants to exit their session
					} else if(command1.equalsIgnoreCase("exit")) {
						terminateClient();
					
					//User wants to remove an event from the server
					} else if(command1.equalsIgnoreCase("remove")) {
						try {
							eventNumber = Integer.parseInt(strTok.nextToken().trim());
						}catch (NumberFormatException e) {
							System.out.println("You did not enter a numerical number correctly!");
							continue;
						}
						removeEvent(eventNumber);
					
					//User wants to view the details of a given event
					} else if(command1.equalsIgnoreCase("detail")) {
						try {
							eventNumber = Integer.parseInt(strTok.nextToken().trim());
						} catch (NumberFormatException e) {
							System.out.println("You did no enter a numerical number correctly!");
							continue;
						}
						eventDetails(eventNumber);
					} else {
						System.out.println("That command is not recognized!");
					}
				}
			}
		}
	}//END waitForCommand()
	
	/*****************************************************************************
	 * Takes the description and the space requested by the user and asks the server
	 * to add it to the database. If successfully added a unique event number is returned.
	 */
	public void addEvent(String theDescription, int theSpaceRequested) {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.addEvent(new Event(theDescription, theSpaceRequested));
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			System.out.println("Event added with event number: " + tempRecieved.getPacketNumber());
		} else {
			System.out.println("There was an error adding the event to the server!");
		}
	}//END addEvent()
	
	/*****************************************************************************
	 * The user enters an event number, if the event is in the server the user is
	 * asked if they are sure they want to remove that event. If they say "yes" then
	 * the event is removed from the server. If they say no, or the event is not found
	 * in the server then no action is performed.
	 */
	public void removeEvent(int theEventNumber) throws IOException {
		PacketContainer tempRecieved = null;
		try {
			//Ask for the event from the server assuming it is valid.
			tempRecieved = (PacketContainer)myRemote.askEvent(theEventNumber);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			//Ask the user if they want to remove the event
			System.out.print("Are you are you want to remove\n" + "Event Number: " + tempRecieved.getPacketEvent().getEventNumber() + "\nDescription: " + 
					tempRecieved.getPacketEvent().getEventDescription() + "\nTotal Space: " + tempRecieved.getPacketEvent().getEventSpace() + "\n(Yes or No)? ");

			
			String yesNo = keyboardIn.readLine();
			if(yesNo.compareToIgnoreCase("yes") == 0) {
				//Event is removed from the server
				tempRecieved = (PacketContainer)myRemote.removeEvent(theEventNumber);
				if(tempRecieved == null) {
					System.out.println("There was a problem removing the event from the server!");
				} else {
					if(tempRecieved.getPacketNumber() != 0) {
						System.out.println("Event removed from database!");
					} else {
						System.out.println("Event not found!");
					}
				}
			}
			
		} else {
			System.out.println("There was an error in retreiving the event from the server!");
		}
	}//END removeEvent()
	
	/*****************************************************************************
	 * The user enters an event number. If the event number is valid then the details
	 * of the event and any corresponding reservations are displayed.
	 */
	public void eventDetails(int theEventNumber) {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.askEvent(theEventNumber);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			//Print the event description.
			Event tempEvent = tempRecieved.getPacketEvent();
			System.out.println("Event Number: " + tempEvent.getEventNumber() + "\nDescription: " + tempEvent.getEventDescription() +
							"\nAvailable Space: " + tempEvent.getSpaceRemaining());
			
			//Print the reservation information
			ArrayList<Reservation> listReservations = tempEvent.getReservationList();
			for(int i = 0; i < tempEvent.getReservationList().size(); i++) {
				System.out.print("     Confirmation Number: " + listReservations.get(i).getConfirmationNumber() +
								"\n     Name: " + listReservations.get(i).getNameForReservation() +
								"\n     Space Reserved: " + listReservations.get(i).getSpaceReserved() + "\n\n");
			}
		} else {
			System.out.println("There was an error retreving the details for this event!");
		}
		
	}//END eventDetails()
	
	/*****************************************************************************
	 * The list of all current events in the database are returned to the user and
	 * displayed
	 */
	public void viewEvents() {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.viewEvents();
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			
			if(tempRecieved.getListEvents().size() == 0) {
				System.out.println("There are no events to view!");
				return;
			}
			//Display all of the events in the terminal
			for(int i = 0; i < tempRecieved.getListEvents().size(); i++) {
				System.out.print("Event Number: " + tempRecieved.getListEvents().get(i).getEventNumber() + "\nDescription: " + 
						tempRecieved.getListEvents().get(i).getEventDescription() + "\nAvailable Space: " + 
						tempRecieved.getListEvents().get(i).getSpaceRemaining() + "\nTotal Space: " +  tempRecieved.getListEvents().get(i).getEventSpace() +"\n\n");
			}
		}
	}//END viewEvents()
	
	/*****************************************************************************
	 * The user enters the event number, space to reserve, and a name to attach
	 * to the reservation. If the event number is valid, and the amount of space
	 * doesn't ask for more then available then the reservation is added to the
	 * event on the server.
	 */
	public void makeReservation(int theEventNumber, int theSpaceRequested, String theName)
	{
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.makeReservation(theEventNumber, theSpaceRequested, theName);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			if(tempRecieved.getPacketNumber() != 0) {
				//The reservation was added, and the confirmation number is printed to the screen
				System.out.println("Confirmation Number: " + tempRecieved.getPacketNumber());
			} else {
				System.out.println("There was not enough space or the event number you entered was not valid!");
			}
		} 
	}//END makeReservation()
	
	/*****************************************************************************
	 * User enters an event number, and a confirmation number. If both are found
	 * to be valid the reservation is displayed to the user. If they confirm the 
	 * deletion then the reservation is removed from the event and the spaces are
	 * freed to the corresponding event.
	 */
	public void deleteReservation(int theEventNumber, int theConfirmationNumber) throws IOException {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.askReservation(theEventNumber, theConfirmationNumber);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			//Ask user for confirmation
			System.out.print("Are you sure you want to delete reservation:" + "\nName: " + tempRecieved.getPacketReservation().getNameForReservation() +
							"\nSpace Reserved: " + tempRecieved.getPacketReservation().getSpaceReserved() + "\n(Yes or No)? ");
			
			String yesNo = keyboardIn.readLine();
			if(yesNo.compareToIgnoreCase("yes") == 0) {
				//User confirmed deletion
				tempRecieved = (PacketContainer)myRemote.deleteReservation(theEventNumber, theConfirmationNumber);
				
				if(tempRecieved != null ) {
					if(tempRecieved.getPacketNumber() != 0) {
						//Server responds saying that the reservation was indeed removed
						System.out.println("The reservation was removed from the database!");
					}
				} else {
					System.out.println("There was an error removing the reservation from the server!");
				}
			}
		} else {
			System.out.println("The event number and confirmation number were not found!");
		}
	}//END deleteReservation()
	
	/*****************************************************************************
	 * Simply closes the connection and ends the client program.
	 */
	public void terminateClient() {
		System.out.println("Manager shutting down");
		System.out.println("Requesting to be removed from Server broadcast");

		try
		{
			myRemote.disconnect(clientRemote);
		}
		catch(Exception e)
		{
			System.out.println("Error: " + e);
			return;
		}

		System.out.println("Program ending");
		System.exit(0);
	}//END terminateClient()



}//END Manager{}





